package cn.initcap.concurrency.concurrency.threadpool;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * corePoolSize
 * 核心线程数，默认情况下核心线程会一直存活，即使处于闲置状态也不会受存keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true。
 * <p>
 * maximumPoolSize
 * 线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时，这个值无效。
 * <p>
 * keepAliveTime
 * 非核心线程的闲置超时时间，超过这个时间就会被回收。
 * <p>
 * unit
 * 指定keepAliveTime的单位，如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
 * <p>
 * workQueue
 * 线程池中的任务队列.
 * 常用的有三种队列，SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue。
 * <p>
 * threadFactory
 * 线程工厂，提供创建新线程的功能。ThreadFactory是一个接口，只有一个方法
 * <p>
 * 线程池规则
 * 线程池的线程执行规则跟任务队列有很大的关系。
 * <p>
 * 下面都假设任务队列没有大小限制：
 * <p>
 * 如果线程数量<=核心线程数量，那么直接启动一个核心线程来执行任务，不会放入队列中。
 * 如果线程数量>核心线程数，但<=最大线程数，并且任务队列是LinkedBlockingDeque的时候，超过核心线程数量的任务会放在任务队列中排队。
 * 如果线程数量>核心线程数，但<=最大线程数，并且任务队列是SynchronousQueue的时候，线程池会创建新线程执行任务，这些任务也不会被放在任务队列中。这些线程属于非核心线程，在任务完成后，闲置时间达到了超时时间就会被清除。
 * 如果线程数量>核心线程数，并且>最大线程数，当任务队列是LinkedBlockingDeque，会将超过核心线程的任务放在任务队列中排队。也就是当任务队列是LinkedBlockingDeque并且没有大小限制时，线程池的最大线程数设置是无效的，他的线程数最多不会超过核心线程数。
 * 如果线程数量>核心线程数，并且>最大线程数，当任务队列是SynchronousQueue的时候，会因为线程池拒绝添加任务而抛出异常。
 * 任务队列大小有限时
 * <p>
 * 当LinkedBlockingDeque塞满时，新增的任务会直接创建新线程来执行，当创建的线程数量超过最大线程数量时会抛异常。
 * SynchronousQueue没有数量限制。因为他根本不保持这些任务，而是直接交给线程池去执行。当任务数量超过最大线程数时会直接抛异常。
 *
 * @author initcap
 * @date Created in 2018/6/18 PM3:48.
 */
@Slf4j
public class ThreadPoolSynchronousQueue {

    private static final int THREAD_SIZE = 10;

    public static void main(String[] args) {
        /*
         * 线程池不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式，这样
         * 的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下:
         * 1)Executors.newFixedThreadPool 和 Executors.newSingleThreadPool:
         * 允许的请求队列长度为 Integer.MAX_VALUE，可能会堆积大量的请求，从而导致 OOM。
         * 2)Executors.newCachedThreadPool 和 Executors.newScheduledThreadPool:
         * 允许的创建线程数量为 Integer.MAX_VALUE，可能会创建大量的线程，从而导致 OOM。
         */
        ThreadFactory nameThreadFactory = new ThreadFactoryBuilder().setNameFormat("ThreadPoolSynchronousQueue").build();
        ExecutorService executorService = new ThreadPoolExecutor(0, THREAD_SIZE, 60L,
                TimeUnit.SECONDS, new SynchronousQueue<>(), nameThreadFactory);
        for (int i = 0; i < 50; i++) {
            final int index = i;
            executorService.execute(() -> log.info("task:{}", index));
        }
        executorService.shutdown();
    }

}
